package cs301.msflags;

import cs301.game.GameHumanPlayer;
import cs301.game.R;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.graphics.Point;
import android.media.AudioManager;
import android.media.SoundPool;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.ToggleButton;

/**
 * The activity class for a human player of Minesweeper Flags - displays the
 * gamestate on the screen and responds to the actions of the user.
 * 
 * @author John Olennikov
 * @author Kyanne Mayfield
 * @author Allie Seibert
 * @author Emilia Holbik
 * @version 12/7/2012
 */

public class MSFlagsHumanPlayer extends GameHumanPlayer implements
		OnClickListener, View.OnTouchListener {

	/**
	 * A reference to my copy of the current game state
	 */
	private MSFlagsGame myMSFlagsGame = null;

	/**
	 * Displays name of player 1 and whether or not it is this player's turn
	 */
	private TextView player1Title;

	/**
	 * Displays name of player 2 and whether or not it is this player's turn
	 */
	private TextView player2Title;

	/**
	 * Displays how many flags player 1 is still able to put on the board
	 */
	private TextView player1Flags;

	/**
	 * Displays how many flags player 2 is still able to put on the board
	 */
	private TextView player2Flags;

	/**
	 * When on, this toggle button allows a player to flag and unflag a space
	 */
	private ToggleButton flagToggleButton;

	/**
	 * Each human player must press this button in order to end his or her turn
	 * and allow the next player to take his or her turn.
	 */
	private Button endTurnButton;

	/**
	 * This button can be pressed any time during the game. It returns to the
	 * player setup GUI, where they can re-enter their personal information and
	 * start a new game.
	 */
	private Button setupGameButton;

	/**
	 * The view which draws the game board.
	 */
	private MSFlagsSurfaceView msv;
	
	/**
	 * The current game board, which holds all the BoardSpaces.
	 */

	private Board board;

	/**
	 * Display the Minesweeper Flags GUI and begin listening for button clicks
	 * from it
	 */
	@Override
	protected void initializeGUI() {
		setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
		// Inflate game screen
		setContentView(R.layout.game_main);

		if (MSFlagsMainActivity.showConfig) {
			// Inflate config screen
			startSetupActivity();

		} else {
			// Setup Listeners
			setupGameListeners();

			// Populate labels
			setupGameContent();
			
			//Get the current board
			board = this.myMSFlagsGame.getBoard();
		}
	}

	/**
	 * Updates the board GUI based on the player's actions
	 */
	@Override
	protected void updateDisplay() {
		setContentView(R.layout.game_main);
	}

	/**
	 * Performs the action that the user indicated, according to which button
	 * was clicked.
	 * 
	 * @param button  the button that was clicked
	 */
	public void onClick(View button) {
		// Set up board GUI buttons

		// determine which player clicked the button
		int myId = this.game.whoseTurn();

		// End turn if user clicked "End Turn" button and has uncovered a tile
		if (button.equals(endTurnButton) && myMSFlagsGame.hasUncovered()) {
			takeAction(new MSFlagsEndTurnAction(myId, board,
					myMSFlagsGame.getFlagsRemaining(myId), board.getUncoveredMine()));

		// If the user clicked the "Settings" button, bring up the config screen
		} else if (button.equals(setupGameButton)) {
			startSetupActivity();
		}
	}

	/**
	 * This method senses which BoardSpace the user touched.
	 * 
	 * @param view  the view which was touched upon
	 * @param event  contains the location of the touch
	 * @return true, the touch event has been handled
	 */
	public boolean onTouch(View view, MotionEvent event) {
		if (event.getAction() == MotionEvent.ACTION_DOWN) {
			boolean gameOver = false;
			// Get the current player's index
			int playerId = this.myMSFlagsGame.whoseTurn();
			// Determine which BoardSpace was touched
			Point temp = board.containsPoint((int) event.getX(),
					(int) event.getY());

			if (temp != null) {
				BoardSpace[][] boardSpaces = board.getBoardSpaceArray();
				
				// User is flagging/unflagging
				if (flagToggleButton.isChecked()) {
					boolean hasFlag;

					// Check if user has flags to place
					hasFlag = this.myMSFlagsGame.getFlagsRemaining(playerId) > 0;
					// Handle the flag/unflag action
					this.myMSFlagsGame
							.setFlagsRemaining(playerId, board.flaggedByPlayer(
									playerId, hasFlag, temp.x, temp.y));
					if(hasFlag)
						mySoundPool.play(flagSound, 1, 1, 1, 0, 1);
					
					// If the user is in "Uncover" mode hasn't yet uncovered a space,
					//uncover the space the user touched.
				} else if (!this.myMSFlagsGame.hasUncovered()) {
					 
					// If the tile contains opponent's flag, set space status 
					// to simply covered (1), so that the space can be uncovered.
					if ((boardSpaces[temp.x][temp.y].isBlueFlagged() && playerId == 1)
							|| (boardSpaces[temp.x][temp.y].isRedFlagged() && playerId == 0)) {
						boardSpaces[temp.x][temp.y].setSpaceStatus(1);
						if (board.uncoverSpace(temp.x, temp.y)) {
							this.myMSFlagsGame.setUncovered(true);
							//play the uncover sound
								mySoundPool.play(uncoverSound, 1, 1, 1, 0, 1);
						}
						// Otherwise, just uncover the space.
					} else {
						if (board.uncoverSpace(temp.x, temp.y)) {
							this.myMSFlagsGame.setUncovered(true);
							//play the uncover sound, making sure that a mine
							//was not uncovered
							if(!board.getUncoveredMine())
								mySoundPool.play(uncoverSound, 1, 1, 1, 0, 1);
						}
					}
					// The user has uncovered a mine
					if (board.getUncoveredMine()) {
						// If this happened on the first turn, reshuffle the mines in the board
						// until a layout of the mines for which the space uncovered
						// doesn't have a mine is found.
						if (this.myMSFlagsGame.isFirstMove()) {
							
							Board newBoard = board;
							while(boardSpaces[temp.x][temp.y].hasMine())
							{
								System.out.println("Reshuffling the mines");
								newBoard = new Board(board.getNumMines(), board.getWidth(), 
									board.getHeight());
							boardSpaces = newBoard.getBoardSpaceArray();
							}
							board = newBoard;
							System.out.println("Uncovered mine = " + board.getUncoveredMine());
							msv.setCurrentBoard(board);
							// Give the view the new board.
							msv.setCurrentBoard(board);
							// Uncover the space.
							if (board.uncoverSpace(temp.x, temp.y)) {
								this.myMSFlagsGame.setUncovered(true);
							}
						
						// If the mine was uncovered on a later turn,
						// the game is over.
						} else {
							takeAction(new MSFlagsEndTurnAction(playerId,
									board, myMSFlagsGame.getFlagsRemaining(playerId),
									board.getUncoveredMine()));
							
							//play the uncover mine sound
							mySoundPool.play(uncoverMineSound, 1, 1, 1, 0, 1);
						}
					}
					
					// Check if all spaces except those containing mines have been
					// uncovered.  If this is the case, the game is over.
					int numUncovered = 0;
					for (int w = 0; w < boardSpaces.length; ++w) {
						for (int h = 0; h < boardSpaces[w].length; ++h) {

							if ((!boardSpaces[w][h].isCovered())) {
								++numUncovered;
							}
						}
					}
					if (numUncovered == (board.getTotalNumSpaces() - board
							.getNumMines())) {
						gameOver = true;
					}
					// If the game is over, and there are any unflagged covered spaces
					// remaining, those spaces get flagged for the current player.
					if (gameOver) {
						for (int w = 0; w < boardSpaces.length; ++w) {
							for (int h = 0; h < boardSpaces[w].length; ++h) {
								// If the board space is covered, but not
								// flagged, its space status is 1.
								if (boardSpaces[w][h].getSpaceStatus() == 1) {
									board.flaggedByPlayer(playerId, true, w, h);
								}
							}
						}
						board.setGameOver(true);
					}
				}

				// Redraw screen
				msv.invalidate();
				if (playerId == 0)
					player1Flags.setText("Flags Remaining: "
							+ myMSFlagsGame.getFlagsRemaining(playerId));
				else
					player2Flags.setText("Flags Remaining: "
							+ myMSFlagsGame.getFlagsRemaining(playerId));

				if (gameOver) {
					// Tell the game class that the game is over.
					takeAction(new MSFlagsEndTurnAction(playerId, board,
							myMSFlagsGame.getFlagsRemaining(playerId),
							board.getUncoveredMine()));
				}
			}

		}
		return true;
	}

	/**
	 * Sets up the listeners for the GUI.
	 */
	public void setupGameListeners() {
		// extract the game state
		myMSFlagsGame = (MSFlagsGame) this.game;

		// set up TextView and Button objects for game GUI
		player1Title = (TextView) this.findViewById(R.id.player_1_name);
		player2Title = (TextView) this.findViewById(R.id.player_2_name);
		player1Flags = (TextView) this.findViewById(R.id.player_1_flags);
		player2Flags = (TextView) this.findViewById(R.id.player_2_flags);

		flagToggleButton = (ToggleButton) this.findViewById(R.id.button_flag);
		endTurnButton = (Button) this.findViewById(R.id.button_end);
		setupGameButton = (Button) this.findViewById(R.id.button_setup);
		
		// Set up the view and its listener
		msv = (MSFlagsSurfaceView) this.findViewById(R.id.surfaceView1);
		msv.setOnTouchListener(this);
		// Give the game board to the view.
		msv.setCurrentBoard(myMSFlagsGame.getBoard());
		

		// set Button listeners for game GUI
		endTurnButton.setOnClickListener(this);
		setupGameButton.setOnClickListener(this);

		// Make sure the "uncover mode" button stays checked or unchecked
		flagToggleButton.setChecked(MSFlagsMainActivity.uncoverMode);
	}
	
	/**
	 * Display whose turn it is and each player's information.
	 */
	public void setupGameContent() {
		// extract the game state
		myMSFlagsGame = (MSFlagsGame) this.game;

		// Display whose turn it is
		int whoseTurn = myMSFlagsGame.whoseTurn();
		if (whoseTurn == 0) {
			player1Title.setText(myMSFlagsGame.getConfig().getSelName(0)
					.toString()
					+ "'s Turn");
			player2Title.setText(myMSFlagsGame.getConfig().getSelName(1)
					.toString());
		} else {

			player1Title.setText(myMSFlagsGame.getConfig().getSelName(0)
					.toString());
			player2Title.setText(myMSFlagsGame.getConfig().getSelName(1)
					.toString()
					+ "'s Turn");
		}
		// Display the number of flags currently available to place
		// for each player.
		player1Flags.setText("Flags Remaining: "
				+ myMSFlagsGame.getFlagsRemaining(0));
		player2Flags.setText("Flags Remaining: "
				+ myMSFlagsGame.getFlagsRemaining(1));

	}

	/**
	 * Start the "configure game" activity
	 */
	public void startSetupActivity() {
		Intent setupIntent = new Intent(MSFlagsHumanPlayer.this,
				MSFlagsSetupActivity.class);

		// Return true if myMSFlagsGame is created
		Boolean isGameCreated = (myMSFlagsGame != null);

		setupIntent.putExtra("isGameCreated", isGameCreated);

		// Random (150) intent id
		startActivityForResult(setupIntent, 150);

		// Prevents animation when switching activities
		overridePendingTransition(0, 0);
	}

	/**
	 * This method is called after the board configuration GUI exits.
	 * The user either wanted to quit game, resume game, or has specified
	 * the board dimension and number of mines for a new game.
	 * 
	 * @param requestCode  indicates where the activity result came from
	 * @param resultCode  the result code from the activity
	 * @param data  an intent containing the information obtained by the
	 *            activity
	 */
	@Override
	public void onActivityResult(int requestCode, int resultCode, Intent data) {
		// extract the game state
		myMSFlagsGame = (MSFlagsGame) this.game;
		
		if (data.getBooleanExtra("quitGame", false)) {
			takeAction(new MSFlagsQuitGameAction(myMSFlagsGame.whoseTurn()));
		} else {
			MSFlagsMainActivity.showConfig = false;

			if (!data.getBooleanExtra("resumeGame", false)) {
				
				// Get the user specified dimensions and number of mines.
				int boardWidth = data.getIntExtra("boardWidth", 20);
				int boardHeight = data.getIntExtra("boardHeight", 20);
				int totalNumMines = data.getIntExtra("totalNumMines", 15);
				
				takeAction(new MSFlagsConfigureBoardAction(
						myMSFlagsGame.whoseTurn(), boardWidth, boardHeight,
						totalNumMines));
			}
		}
	}
}